/**
 * 
 */
package com.jahentao.integrationTest.case13;

import java.io.DataInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.SocketTimeoutException;
import java.util.Properties;
/**
 * 
 * @author jahen
 * @date 2016年8月8日
 * @time 上午9:38:34
 * @category Socket编程
 */
public class DownloadThread extends Thread {

	private int BUFFER_SIZE = 1024 * 4; // 缓冲区大小
	
	private DownloadInfo downloadInfo;
	private MultiThreadDownloadJFrame frame;
	private Properties properties;

	private boolean isContinued = false;
	
	public DownloadThread(DownloadInfo downloadInfo, MultiThreadDownloadJFrame frame, Properties properties, boolean isContinued){
		this.downloadInfo = downloadInfo;
		this.frame = frame;
		this.properties = properties;
		this.isContinued = isContinued;
	}
	
	public DownloadThread(DownloadInfo downloadInfo, MultiThreadDownloadJFrame frame, Properties properties, boolean isContinued, int BUFFER_SIZE){
		this.downloadInfo = downloadInfo;
		this.frame = frame;
		this.properties = properties;
		this.isContinued = isContinued;
		this.BUFFER_SIZE=BUFFER_SIZE;
	}
	
	@Override
	public void run() {
		RandomAccessFile rafW = null;
		DataInputStream dis = null;
		try {
			// 获得并计算下载信息
			int index = downloadInfo.getIndex();
			long start = (isContinued) ? downloadInfo.getAmount() + downloadInfo.getStart() : downloadInfo.getStart();
			long end = downloadInfo.getEnd();

			// 该范围内已经完成，没必要再请求数据了
			if (start == end) {
				return;
			}

			// 设置下载文件路径
			rafW = new RandomAccessFile(downloadInfo.getOutPath() +"/"+ properties.getProperty("fileName"),"rw");
			rafW.seek(start); // 定位
			
			// 获得文件写入流
			HttpURLConnection connection = (HttpURLConnection)downloadInfo.getUrl().openConnection();
			
			// 以防网络异常的情况下，可能会导致程序僵死而不继续往下执行
			// 设置连接主机超时
			connection.setConnectTimeout(30000);
			// 设置从主机读取数据超时
			connection.setReadTimeout(30000); 
			
			// 设置范围
			connection.setRequestProperty("Range", "bytes="+start+"-"+(end-1));
			// TODO 当出现连接超时的情形，要主动重连
			connection.connect();
			dis = new DataInputStream(connection.getInputStream());
			// 读写文件
			byte[] buffer = new byte[BUFFER_SIZE];
			int len = -1;
			// 添加 判断是否停止
			while(!this.isInterrupted() && (len=dis.read(buffer))!=-1) {
				rafW.write(buffer,0,len);
//				updateProp(index,len);
				// 更新完成量
				properties.setProperty("thread."+index+".amount", (Integer.parseInt(properties.getProperty("thread."+index+".amount"))+len)+"");
				if (frame.updateProgressBars(index, len)) {
					return;
				}
			}
			/*if(this.isInterrupted()){ // 停止标记
				FileOutputStream fos = new FileOutputStream(properties.getProperty("metadataFile"));
				properties.store(fos, "interruped");
			}*/
			//正确的写法
			/*while((len=dis.read(buffer))!=-1){
				rafW.write(buffer,0,len);
				updateProp(index,len);
				frame.updateProgressBars(index, len);
			}*/
			//偶然间发现的，怎么都找不到错误原因，本以为等价的写法
			/* int loop = (int)(maximum/BUFFER_SIZE);
			 for(int j=0; j<loop; j++){
			 	dis.read(buffer);
			 	rafW.write(buffer);
			 	frame.updateProgressBars(index, BUFFER_SIZE);
			 }
			 int remain = (int) (maximum % BUFFER_SIZE);
			 if(remain!=0){
			 	byte[] leftData = new byte[remain];
			 	dis.read(leftData);
			 	rafW.write(leftData);
			 	frame.updateProgressBars(index, remain);
			 }*/
		} catch (SocketTimeoutException e) {
			System.out.println("连接超时");
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}finally{
			if (!frame.isFinished()) {
				updateProp();
			}
			
			if(dis!=null)
				try {
					dis.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			
			if(rafW!=null)
				try {
					rafW.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
		}
	}

	/**
	 * 断点续传信息记录
	 */
	private synchronized void updateProp() {
		try {
			File metadataFile = null;
			if((metadataFile = new File(properties.getProperty("metadataFile"))).exists())
				metadataFile.delete();
			FileOutputStream fos = new FileOutputStream(properties.getProperty("metadataFile"));
			properties.store(fos, "update info");
			fos.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
}
